#include "MySQLMan.h"
//#include "log4z.h"


CMySQLMan::CMySQLMan()
{
	memset(m_host, 0x00, sizeof(m_host));
	memset(m_user, 0x00, sizeof(m_user));
	memset(m_password, 0x00, sizeof(m_password));
	memset(m_db, 0x00, sizeof(m_db));
	m_thread.Start(ThreadProc, this);
}

CMySQLMan::~CMySQLMan()
{
	for (ITER_CONNECTION_HANDLE_LIST iter = m_lsBusyList.begin(); iter != m_lsBusyList.end(); iter++)
	{
		mysql_close((*iter));
	}

	for (ITER_CONNECTION_HANDLE_LIST iter = m_lsIdleList.begin(); iter != m_lsIdleList.end(); iter++)
	{
		mysql_close((*iter));
	}
	m_thread.Stop();
}

bool CMySQLMan::ConnectDB(const char* host, const char* user, const char* password, const char* db, unsigned int port/* =3306 */)
{
	strncpy(m_host, host, sizeof(m_host) - 1);
	strncpy(m_user, user, sizeof(m_user) - 1);
	strncpy(m_password, password, sizeof(m_password) - 1);
	strncpy(m_db, db, sizeof(m_db) - 1);
	m_port = port;
	//	bool mysql_real_connect_flag = false;

		//同时打开CONNECTION_NUM个连接
	try
	{
		for (int i = 0; i < CONNECTION_NUM; ++i)
		{
			MYSQL* pMySql = mysql_init((MYSQL*)NULL);
			if (pMySql != NULL)
			{
				unsigned int timeout = 3;
				if (mysql_options(pMySql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout))
				{
					printf("mysql_options Error %u (%s)\n", mysql_errno(pMySql),
						mysql_error(pMySql));
					return false;
				}

				if (!mysql_real_connect(pMySql, m_host, m_user, m_password, m_db, m_port, NULL, 0))
				{
					OutErrors(pMySql);
					//LOGFMTE("%s", OutErrors(pMySql));
					i = 0;
#ifdef WIN32
					Sleep(1000);
#else
					usleep(1000 * 1000);
#endif
					//					return false;
				}
				else {
					my_bool reConnect = 1;
					if (mysql_options(pMySql, MYSQL_OPT_RECONNECT, &reConnect))
					{
						printf("mysql_options Error %u (%s)", mysql_errno(pMySql),
							mysql_error(pMySql));
						return false;
					}

					if (mysql_set_character_set(pMySql, "utf8mb4") != 0)
					{
						printf("mysql_set_character_set Error %u (%s)", mysql_errno(pMySql),
							mysql_error(pMySql));
						return 5;
					}
				}
				m_lsIdleList.push_back(pMySql);
			}
			else {
				printf("mysql_init %u (%s)", mysql_errno(pMySql),
					mysql_error(pMySql));
			}
		}
	}
	catch (...)
	{
		return false;
	}
	return true;
}

#ifdef WIN32
DWORD WINAPI CMySQLMan::ThreadProc(LPVOID lpParameter)
{
#ifndef USE_LIBUV
	CMySQLMan* pThis = reinterpret_cast<CMySQLMan*>(lpParameter);
	if (pThis)
	{
		pThis->ThreadHandle();
	}
#endif

	return 0;
}
#else
void* CMySQLMan::ThreadProc(void* lpParameter)
{
#ifndef USE_LIBUV
	CMySQLMan* pThis = reinterpret_cast<CMySQLMan*>(lpParameter);
	if (pThis)
	{
		pThis->ThreadHandle();
	}
#endif

	return 0;
}
#endif

void CMySQLMan::ThreadHandle()
{
	while (m_thread.IsInterrupted())
	{
#ifdef WIN32
		Sleep(5 * 1000);
#else
		usleep(5 * 1000 * 1000);
#endif
		std::lock_guard<std::mutex> lck(_mtx);
#if 0
		CONNECTION_HANDLE_LIST::iterator m_lsIdleListIterator;
		m_lsIdleListIterator = m_lsIdleList.begin();
		while (m_lsIdleListIterator != m_lsIdleList.end())
		{
			mysql_ping(*m_lsIdleListIterator);
			m_lsIdleListIterator++;
			m_lsIdleListIterator->connector_fd;
		}
#endif
		for (ITER_CONNECTION_HANDLE_LIST iter = m_lsIdleList.begin(); iter != m_lsIdleList.end(); iter++)
		{
			try {
				mysql_ping((*iter));
			}
			catch (...)
			{
				printf("%s\n", OutErrors(*iter));
				continue;
			}
		}
}
}

MYSQL* CMySQLMan::GetIdleMySql()
{
	MYSQL* pMySql = NULL;
	std::lock_guard<std::mutex> lck(_mtx);
	printf("m_lsIdleList : %d\n", m_lsIdleList.size());
	printf("m_lsBusyList : %d\n", m_lsBusyList.size());
	if (m_lsIdleList.size() > 0)
	{
		pMySql = m_lsIdleList.front();
		printf("%p\n", pMySql);
		m_lsIdleList.pop_front();
		m_lsBusyList.push_back(pMySql);
	}
	else
	{
		pMySql = NULL;
	}

	return pMySql;
}

void CMySQLMan::SetIdleMysql(MYSQL* pMySql)
{
	std::lock_guard<std::mutex> lck(_mtx);
	m_lsBusyList.remove(pMySql);
	m_lsIdleList.push_back(pMySql);
}

MYSQL_RES* CMySQLMan::SelectRecord(const char* szSql)
{
	MYSQL* pMySql = GetIdleMySql();
	if (pMySql == NULL)
	{
		//	LOGFMTE("pMySql NULL ");
		return NULL;
	}

	if (mysql_query(pMySql, szSql)) {
		//		LOGFMTE("myqlError:%s", mysql_error(pMySql));
		return NULL;
	}
	MYSQL_RES* myquery = NULL;
	myquery = mysql_store_result(pMySql);
	SetIdleMysql(pMySql);

	return myquery;
}

bool CMySQLMan::InsertRecord(const char* szSql)
{
	bool bRet = false;
	MYSQL* pMySql = GetIdleMySql();
	if (pMySql == NULL)
	{
		//		LOGFMTE("pMySql NULL");
		return false;
	}
	int nRet = 0;
	if (!mysql_query(pMySql, szSql))
	{
		bRet = true;
	}
	else
	{
		//		printf("[%s] line:%d myqlError:%s\n", __FUNCTION__, __LINE__, mysql_error(pMySql));
		//		LOGFMTE("myqlError:%s", mysql_error(pMySql));
	}
	SetIdleMysql(pMySql);

	return bRet;
}

bool CMySQLMan::UpdateRecord(const char* szSql)
{
	bool bRet = false;
	MYSQL* pMySql = GetIdleMySql();
	if (pMySql == NULL)
	{
		return false;
	}
	if (!mysql_query(pMySql, szSql))
	{
		bRet = true;
	}
	else
	{
		//		printf("[%s] line:%d myqlError:%s\n", __FUNCTION__, __LINE__, mysql_error(pMySql));
		//		LOGFMTE("myqlError:%s", mysql_error(pMySql));
	}
	SetIdleMysql(pMySql);

	return bRet;
}

bool CMySQLMan::DelRecord(const char* szSql)
{
	bool bRet = false;
	MYSQL* pMySql = GetIdleMySql();
	if (pMySql == NULL)
	{
		return false;
	}
	if (!mysql_query(pMySql, szSql))
	{
		bRet = true;
	}
	else
	{
		//		printf("[%s] line:%d myqlError:%s\n", __FUNCTION__, __LINE__, mysql_error(pMySql));
		//		LOGFMTE("myqlError:%s", mysql_error(pMySql));
	}
	SetIdleMysql(pMySql);

	return bRet;
}

bool CMySQLMan::SelectDB(const char* szDB)
{
	bool bRet = false;
	MYSQL* pMySql = GetIdleMySql();
	if (pMySql == NULL)
	{
		return false;
	}
	if (mysql_select_db(pMySql, szDB))
		bRet = false;
	else
		bRet = true;
	SetIdleMysql(pMySql);

	return bRet;
}

my_ulonglong CMySQLMan::GetRowNum(MYSQL_RES* myquery)
{
	return mysql_num_rows(myquery);
}

MYSQL_ROW CMySQLMan::GetRecord(MYSQL_RES* myquery)
{
	m_row = mysql_fetch_row(myquery);

	return m_row;
}

unsigned int CMySQLMan::GetFieldNum(MYSQL_RES* myquery)
{
	return mysql_num_fields(myquery);
}

void CMySQLMan::FreeRecord(MYSQL_RES* myquery)
{
	mysql_free_result(myquery);
}

//int CMySQLMan::CreateDB(char *db)
//{
// return mysql_create_db(&m_mysql,db);
//}

void CMySQLMan::SeekData(MYSQL_RES* myquery, int offset)
{
	mysql_data_seek(myquery, offset);
}


char* CMySQLMan::OutErrors(MYSQL* pMySql)
{
	return const_cast<char*>(mysql_error(pMySql));
}

bool CMySQLMan::IsEnd(MYSQL_RES* myquery)
{
	return !!mysql_eof(myquery);
}

char* CMySQLMan::GetFieldName(MYSQL_RES* myquery, int FieldNum)
{
	m_field = mysql_fetch_field_direct(myquery, FieldNum);

	return m_field->name;
}

char* CMySQLMan::GetClientInfo()
{
	return const_cast<char*>(mysql_get_client_info());
}

char* CMySQLMan::GetHostInfo()
{
	MYSQL* pMySql = GetIdleMySql();
	if (pMySql == NULL)
	{
		return NULL;
	}
	return const_cast<char*>(mysql_get_host_info(pMySql));
}

int CMySQLMan::GetProtocolInfo()
{
	int iRet = 0;
	MYSQL* pMySql = GetIdleMySql();
	if (pMySql == NULL)
	{
		return NULL;
	}
	iRet = mysql_get_proto_info(pMySql);
	SetIdleMysql(pMySql);

	return iRet;
}

char* CMySQLMan::GetServerInfo()
{
	static char szRet[1024] = { 0 };
	MYSQL* pMySql = GetIdleMySql();
	if (pMySql == NULL)
	{
		return NULL;
	}
	strncpy(szRet, const_cast<char*>(mysql_get_server_info(pMySql)), sizeof(szRet) - 1);
	SetIdleMysql(pMySql);

	return szRet;
}

char* CMySQLMan::GetState()
{
	MYSQL* pMySql = GetIdleMySql();
	if (pMySql == NULL)
	{
		return NULL;
	}
	static char szRet[1024] = { 0 };
	strncpy(szRet, const_cast<char*>(mysql_stat(pMySql)), sizeof(szRet) - 1);
	SetIdleMysql(pMySql);

	return szRet;
}

bool CMySQLMan::SetCharset()
{
	bool bRet = false;
	char szSql[50];
	strcpy(szSql, "set names gb2312");
	MYSQL* pMySql = GetIdleMySql();
	if (pMySql == NULL)
	{
		return false;
	}
	if (!mysql_query(pMySql, szSql))
		bRet = true;
	SetIdleMysql(pMySql);

	return bRet;
}

//LOCK TABLES tbl1 READ, tbl2 WRITE
bool CMySQLMan::LockTable(const char* TableName, const char* Priority)
{
	bool bRet = false;
	char szSql[50];
	sprintf(szSql, "LOCK TABLES %s %s", TableName, Priority);
	MYSQL* pMySql = GetIdleMySql();
	if (pMySql == NULL)
	{
		return false;
	}
	if (!mysql_query(pMySql, szSql))
		bRet = true;
	SetIdleMysql(pMySql);

	return bRet;
}

bool CMySQLMan::UnlockTable()
{
	bool bRet = false;
	MYSQL* pMySql = GetIdleMySql();
	if (pMySql == NULL)
	{
		return false;
	}
	if (!mysql_query(pMySql, "UNLOCK TABLES"))
		bRet = true;
	SetIdleMysql(pMySql);

	return bRet;
}